using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using AutumnEngine.Modules;
using System.IO;


namespace AutumnEngine
{    
    public partial class Scene
    {
        /// <summary>
        /// Saves the scene to the specified path.
        /// </summary>
        /// <param name="path">The path.</param>
        public void Save(string path)
        {
            //Nodes =
            /*
             * Node
             * Button
             * Label
             * TextButton
             * SpriteNode
             * PhysicSpriteNode
             * */
            //Todo
           /*  Idea is as follows
             * 6 stage process, one for each type of node.
             * Stage 1
             * Sprite nodes with physics.            
             * Binary writer.
             * write number of physic nodes
             * write they're names
             * write texture names
             * right X poisition
             * write Y position
             * write color R, B,G and A
             * write scales
             * write rotations             
             * Repeat for other stages
             * when finished all stages             
             * write the paths of all used textures             
           */

            //Open
            string fix = "";
#if WINDOWS
            fix = path;
#else
            throw new Exception("Saving is not supported on platforms other than PC.");
#endif


            FileStream fs = File.Open(fix, FileMode.OpenOrCreate);
            BinaryWriter writer = new BinaryWriter(fs);
            Dictionary<string, Node> tmp = new Dictionary<string, Node>();
            Dictionary<string, string> paths = new Dictionary<string, string>();
            Dictionary<string, string> fonts = new Dictionary<string, string>();
            ////////////////////////////////////
            #region Write Nodes
            foreach (KeyValuePair<string, Node> kvp in this.Nodes)
            {
                if (kvp.Value.GetType() == typeof(Node))
                {
                    tmp.Add(kvp.Key, kvp.Value);
                }
            }
            writer.Write(tmp.Count);
            foreach (KeyValuePair<string, Node> kvp in tmp)
            {
                writer.Write(kvp.Key);
                writer.Write((int)kvp.Value.Position.X);
                writer.Write((int)kvp.Value.Position.Y);
                writer.Write(kvp.Value.CameraTranslation);
            }
            tmp.Clear();

            #endregion

            #region Write Markers
            foreach (KeyValuePair<string, Node> kvp in this.Nodes)
            {
                if (kvp.Value.GetType() == typeof(Marker))
                {
                    tmp.Add(kvp.Key, kvp.Value);
                }
            }
            writer.Write(tmp.Count);
            foreach (KeyValuePair<string, Node> kvp in tmp)
            {
                writer.Write(kvp.Key);
                writer.Write((int)kvp.Value.Position.X);
                writer.Write((int)kvp.Value.Position.Y);
                writer.Write(kvp.Value.CameraTranslation);
            }
            tmp.Clear();

            #endregion

            #region Write SpriteNodes

            //Formwat
            /*
             * Pos X
             * Pos Y
             * StrTexture
             * Scale X
             * Scale Y
             * Rotation
             * Origin X
             * Origin Y
             * Color R
             * Color G
             * Color B
             * Color A
            */
            foreach (KeyValuePair<string, Node> kvp in this.Nodes)
            {
                if (kvp.Value.GetType() == typeof(SpriteNode))
                {
                    tmp.Add(kvp.Key, kvp.Value);
                }
            }
            writer.Write(tmp.Count);
            foreach (KeyValuePair<string, Node> kvp in tmp)
            {
                writer.Write(kvp.Key);
                writer.Write((int)kvp.Value.Position.X);
                writer.Write((int)kvp.Value.Position.Y);
                writer.Write(((SpriteNode)(kvp.Value)).Texture);
                try
                {
                    if (((SpriteNode)(kvp.Value)).Texture != "Blank")
                    paths.Add(((SpriteNode)(kvp.Value)).Texture, Engine.Modules.TextureManager.TexturePathFromKey(((SpriteNode)(kvp.Value)).Texture));
                }
                catch { }
                writer.Write((int)((SpriteNode)(kvp.Value)).Scale.X);
                writer.Write((int)((SpriteNode)(kvp.Value)).Scale.Y);
                writer.Write((double)((SpriteNode)(kvp.Value)).Rotation);
                writer.Write((int)((SpriteNode)(kvp.Value)).Origin.X);
                writer.Write((int)((SpriteNode)(kvp.Value)).Origin.Y);
                writer.Write(((SpriteNode)(kvp.Value)).Color.R);
                writer.Write(((SpriteNode)(kvp.Value)).Color.G);
                writer.Write(((SpriteNode)(kvp.Value)).Color.B);
                writer.Write(((SpriteNode)(kvp.Value)).Color.A);
                writer.Write(kvp.Value.CameraTranslation);
            }
            tmp.Clear();
            #endregion
            

            #region Write PhysicSpriteNodes

            //Formwat
            /*
             * Pos X
             * Pos Y
             * StrTexture
             * Scale X
             * Scale Y
             * Rotation
             * Origin X
             * Origin Y
             * Color R
             * Color G
             * Color B
             * Color A
             * byte BodyType
             * int width
             * int height
             * double mass
             * bool static
            */
            foreach (KeyValuePair<string, Node> kvp in this.Nodes)
            {
                if (kvp.Value.GetType() == typeof(PhysicsSpriteNode))
                {
                    tmp.Add(kvp.Key, kvp.Value);
                }
            }
            writer.Write(tmp.Count);
            foreach (KeyValuePair<string, Node> kvp in tmp)
            {
                writer.Write(kvp.Key);
                writer.Write((int)kvp.Value.Position.X);
                writer.Write((int)kvp.Value.Position.Y);
                writer.Write(((PhysicsSpriteNode)(kvp.Value)).Texture);
                try
                {
                    if(((PhysicsSpriteNode)(kvp.Value)).Texture != "Blank")
                    {
                    paths.Add(((SpriteNode)(kvp.Value)).Texture, Engine.Modules.TextureManager.TexturePathFromKey(((SpriteNode)(kvp.Value)).Texture));
                    }
                }
                catch (Exception) { }
                writer.Write((int)((PhysicsSpriteNode)(kvp.Value)).Scale.X);
                writer.Write((int)((PhysicsSpriteNode)(kvp.Value)).Scale.Y);
                writer.Write((double)((PhysicsSpriteNode)(kvp.Value)).Rotation);
                writer.Write((int)((PhysicsSpriteNode)(kvp.Value)).Origin.X);
                writer.Write((int)((PhysicsSpriteNode)(kvp.Value)).Origin.Y);
                writer.Write(((PhysicsSpriteNode)(kvp.Value)).Color.R);
                writer.Write(((PhysicsSpriteNode)(kvp.Value)).Color.G);
                writer.Write(((PhysicsSpriteNode)(kvp.Value)).Color.B);
                writer.Write(((PhysicsSpriteNode)(kvp.Value)).Color.A);
                writer.Write((byte)(((PhysicsSpriteNode)(kvp.Value)).Type));
                writer.Write((((PhysicsSpriteNode)(kvp.Value)).Width));
                writer.Write((((PhysicsSpriteNode)(kvp.Value)).Height));
                if ((double)(((PhysicsSpriteNode)(kvp.Value)).Mass) <= 0)
                    throw new Exception("0 mass on " + kvp.Key);
                writer.Write((double)(((PhysicsSpriteNode)(kvp.Value)).Mass));
                writer.Write((bool)(((PhysicsSpriteNode)(kvp.Value)).Static));
                writer.Write(kvp.Value.CameraTranslation);
            }

            //Label nodes
            #region Write Labels

            //Formwat
            /*
             * Pos X
             * Pos Y
             * StrText
             * StrFont
             * dobule scale
             * Rotation
             * Origin X
             * Origin Y
             * Color R
             * Color G
             * Color B
             * Color A
            */
            tmp.Clear();
            foreach (KeyValuePair<string, Node> kvp in this.Nodes)
            {
                if (kvp.Value.GetType() == typeof(LabelNode))
                {
                    tmp.Add(kvp.Key, kvp.Value);
                }
            }
            writer.Write(tmp.Count);
            foreach (KeyValuePair<string, Node> kvp in tmp)
            {
                writer.Write(kvp.Key);
                writer.Write((int)kvp.Value.Position.X);
                writer.Write((int)kvp.Value.Position.Y);
                writer.Write(((LabelNode)(kvp.Value)).Text);
                writer.Write(((LabelNode)(kvp.Value)).Font);
                writer.Write((double)(((LabelNode)(kvp.Value)).Scale));
                writer.Write((double)(((LabelNode)(kvp.Value)).Rotation));
                writer.Write((int)((LabelNode)(kvp.Value)).Origin.X);
                writer.Write((int)((LabelNode)(kvp.Value)).Origin.Y);
                writer.Write(((LabelNode)(kvp.Value)).Color.R);
                writer.Write(((LabelNode)(kvp.Value)).Color.G);
                writer.Write(((LabelNode)(kvp.Value)).Color.B);
                writer.Write(((LabelNode)(kvp.Value)).Color.A);
                writer.Write(kvp.Value.CameraTranslation);
                try
                {
                    if (((LabelNode)(kvp.Value)).Font != "Engine")
                    fonts.Add(((LabelNode)(kvp.Value)).Font, Engine.Modules.FontManager.GetPathFromKey(((LabelNode)(kvp.Value)).Font));
                }
                catch (Exception) { }
            }
            tmp.Clear();
            #endregion
            
            tmp.Clear();
            #endregion
            
            //Write all the paths for the needed textures.
            writer.Write(paths.Count);
            //Names
            foreach (string n in paths.Keys)
            {
                writer.Write(n);
            }
            //Paths
            foreach (string n in paths.Values)
            {
                writer.Write(n);
            }
            
            writer.Write(fonts.Count);
            foreach (string n in fonts.Keys)
                writer.Write(n);
            //Paths
            foreach (string n in fonts.Values)
                writer.Write(n);

            ////////////////////////////////////
            //Close
            writer.Close();
            fs.Close();
        }
    }
}